package com.erbantou.filemanage.service;

import com.google.common.collect.Multimap;
import io.minio.CreateMultipartUploadResponse;
import io.minio.MinioClient;
import io.minio.ObjectWriteResponse;
import io.minio.UploadPartResponse;
import io.minio.errors.*;
import io.minio.messages.Part;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class CustomMinioClient extends MinioClient {

    public CustomMinioClient(MinioClient client) {
        super(client);
    }

    public CreateMultipartUploadResponse customCreateMultipartUpload(String bucketName, String region, String objectName, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException {
        return this.createMultipartUpload(bucketName, region, objectName, headers, extraQueryParams);
    }

    public UploadPartResponse customUploadPart(String bucketName, String region, String objectName, Object data, int length, String uploadId, int partNumber, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException {
        return this.uploadPart(bucketName, region, objectName, data, length, uploadId, partNumber, extraHeaders, extraQueryParams);
    }

    public ObjectWriteResponse customPutObject(String bucketName, String region, String objectName, Object data, int length, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException {
        return this.putObject(bucketName, region, objectName, data, length, headers, extraQueryParams);
    }

    public ObjectWriteResponse customCompleteMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException {
        return this.completeMultipartUpload(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams);
    }

    public long getAvailableSize(Object data, long expectedReadSize) throws IOException, InternalException {
        if (!(data instanceof BufferedInputStream stream)) {
            throw new InternalException("data must be BufferedInputStream. This should not happen.  Please report to https://github.com/minio/minio-java/issues/", null);
        } else {
            stream.mark((int) expectedReadSize);
            byte[] buf = new byte[16384];

            long totalBytesRead;
            int bytesRead;
            for (totalBytesRead = 0L; totalBytesRead < expectedReadSize; totalBytesRead += bytesRead) {
                long bytesToRead = expectedReadSize - totalBytesRead;
                if (bytesToRead > (long) buf.length) {
                    bytesToRead = buf.length;
                }

                bytesRead = stream.read(buf, 0, (int) bytesToRead);
                if (bytesRead < 0) {
                    break;
                }
            }

            stream.reset();
            return totalBytesRead;
        }
    }
}

